using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using MvpFramework.Specifications;
using StructureMap;

namespace MvpFramework.Infastructure
{
    /// <summary>
    /// Factory for constructing the proper validators for Views
    /// </summary>
    public class SpecificationFactory
    {
        /// <summary>
        /// Returns all the <see cref="Specification{T}"/> for a View
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public virtual ReadOnlyCollection<Specification<T>> GetSpecificationsFor<T>()
        {
            var types = FindSpecifications<T>();
            var specifications = new List<Specification<T>>(types.Count);
            foreach (var type in types)
            {
                specifications.Add((Specification<T>)ObjectFactory.GetInstance(type));
            }
            return new ReadOnlyCollection<Specification<T>>(specifications);

        }
        private static Collection<Type> FindSpecifications<T>() 
        {
            return GetSpecsUsingReflection<T>();
        }

        private static Collection<Type> GetSpecsUsingReflection<T>() 
        {
            var specs = new List<Type>();
            var allTypes = new List<Type>(typeof (T).Assembly.GetTypes());
            var correctTypes = new List<Type>(allTypes.Where(IsAViewSpecification<T>));
            correctTypes.ForEach(specs.Add);
            return new Collection<Type>(specs);
        }

        private static bool IsAViewSpecification<T>(Type t)
        {
            return t.GetInterfaces().FirstOrDefault(i => i == typeof (IViewSpecification<T>)) != null;
        }
    }
}